package com.zoffy.catdiarybackend.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zoffy.catdiarybackend.common.BusinessException;
import com.zoffy.catdiarybackend.common.IdRequest;
import com.zoffy.catdiarybackend.common.PageRequest;
import com.zoffy.catdiarybackend.common.StateCode;
import com.zoffy.catdiarybackend.model.dto.article.*;
import com.zoffy.catdiarybackend.model.entity.Article;
import com.zoffy.catdiarybackend.model.enums.article.ArticleStatus;
import com.zoffy.catdiarybackend.model.enums.article.ArticleType;
import com.zoffy.catdiarybackend.model.vo.ArticleTinyVo;
import com.zoffy.catdiarybackend.model.vo.ArticleVo;
import com.zoffy.catdiarybackend.model.vo.Permissions;
import com.zoffy.catdiarybackend.model.vo.UserVo;
import com.zoffy.catdiarybackend.service.ArticleService;
import com.zoffy.catdiarybackend.mapper.ArticleMapper;
import com.zoffy.catdiarybackend.service.FriendshipService;
import com.zoffy.catdiarybackend.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 86170
 * @description 针对表【article】的数据库操作Service实现
 * @createDate 2024-06-09 12:15:17
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article>
        implements ArticleService {
    @Value("${application.collaboration.salt}")
    private String SALT;
    @Value("${application.collaboration.roomClosePath}")
    private String roomClosePath;
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource
    private UserService userService;
    @Resource
    private FriendshipService friendshipService;


    @Override
    public long createArticle(HttpServletRequest request, ArticleCreateRequest articleCreateRequest) {
        UserVo userVo = userService.getUserVo(request);
        if (userVo == null) {
            throw new BusinessException(StateCode.NOT_LOGIN_ERROR);
        }
        //请求参数校验
        String title = articleCreateRequest.getTitle();
        String content = articleCreateRequest.getContent();
        String type = articleCreateRequest.getType();
        String status = articleCreateRequest.getStatus();
        String description = articleCreateRequest.getDescription();
        if (StringUtils.isAnyBlank(title, content, type, status)) {
            throw new BusinessException(StateCode.PARAMS_DELETION);
        }
        ArticleType articleType = ArticleType.getEnumByValue(type);
        ArticleStatus articleStatus = ArticleStatus.getEnumByValue(status);
        if (articleType == null || articleStatus == null) {
            throw new BusinessException(StateCode.PARAMS_ERROR, "不支持的文件类型");
        }
        //创建文章
        Article article = new Article();
        article.setTitle(title);
        article.setContent(content);
        article.setDescription(description);
        article.setPicture(null);
        article.setType(type);
        Permissions permissions = new Permissions();
        permissions.setCollaborative(false);
        article.setPermissions(JSON.toJSONString(permissions));
        article.setStatus(status);
        article.setUserId(userVo.getId());
        this.save(article);
        return article.getId();
    }

    @Override
    public IPage<ArticleTinyVo> listArticleTinyVoByPage(PageRequest pageRequest) {
        int page = pageRequest.getPage();
        int pageSize = pageRequest.getPageSize();
        //todo 权限校验
        QueryWrapper<Article> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status","public");
        Page<Article> articlePage = this.page(new Page<>(page, pageSize), queryWrapper);
        return articlePage.convert(ArticleTinyVo::obj2TinyVo);
    }


    @Override
    public ArticleVo getArticleVoById(HttpServletRequest request,IdRequest idRequest) {
        long id = idRequest.getId();
        Article article = this.getById(id);
        String status = article.getStatus();
        if(ArticleStatus.PUBLIC.getStatus().equals(status)){
            return ArticleVo.obj2Vo(article);
        }
        UserVo userVo = userService.getUserVo(request);
        if(userVo==null){
            throw new BusinessException(StateCode.NO_AUTH_ERROR);
        }
        if(ArticleStatus.SHARE_WITH_FRIEND.getStatus().equals(status)){
            if(userVo.getId()!=article.getUserId() || friendshipService.checkFriend(article.getUserId(),userVo.getId())){
                return ArticleVo.obj2Vo(article);
            }
            throw new BusinessException(StateCode.NO_AUTH_ERROR);
        }
        if(ArticleStatus.PRIVATE.getStatus().equals(status)){
            if(userVo.getId()!=article.getUserId()){
                throw new BusinessException(StateCode.NO_AUTH_ERROR);
            }
            return ArticleVo.obj2Vo(article);
        }
        return ArticleVo.obj2Vo(article);
    }

    @Override
    public boolean updateArticleById(ArticleUpdateRequest articleUpdateRequest, HttpServletRequest request) {
        UserVo userVo = userService.getUserVo(request);
        if (userVo == null) {
            throw new BusinessException(StateCode.NOT_LOGIN_ERROR);
        }
        long id = articleUpdateRequest.getId();
        String title = articleUpdateRequest.getTitle();
        String content = articleUpdateRequest.getContent();
        String description = articleUpdateRequest.getDescription();
        String status = articleUpdateRequest.getStatus();
        Article article = this.getById(id);
        if (userVo.getId() != article.getUserId()) {
            throw new BusinessException(StateCode.NO_AUTH_ERROR, "你没有权限操作该文档");
        }
        Article newArticle = new Article();
        newArticle.setId(id);
        newArticle.setTitle(title);
        newArticle.setContent(content);
        newArticle.setDescription(description);
        newArticle.setStatus(status);
        return this.updateById(article);
    }

    @Override
    public IPage<ArticleTinyVo> listOwnArticleTinyVoByPage(HttpServletRequest request, PageRequest pageRequest) {
        UserVo userVo = userService.getUserVo(request);
        if (userVo == null) {
            throw new BusinessException(StateCode.NOT_LOGIN_ERROR);
        }
        int page = pageRequest.getPage();
        int pageSize = pageRequest.getPageSize();
        QueryWrapper<Article> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userVo.getId());
        Page<Article> articlePage = this.page(new Page<>(page, pageSize), queryWrapper);
        return articlePage.convert(ArticleTinyVo::obj2TinyVo);
    }

    @Override
    public boolean updatePermissionById(HttpServletRequest request, PermissionUpdateRequest permissionUpdateRequest) {
        UserVo userVo = userService.getUserVo(request);
        if (userVo == null) {
            throw new BusinessException(StateCode.NOT_LOGIN_ERROR);
        }
        long articleId = permissionUpdateRequest.getArticleId();
        Article article = this.getById(articleId);
        if(article==null || article.getUserId()!=userVo.getId()){
            return false;
        }
        Permissions permissions = permissionUpdateRequest.getPermissions();
        if (!permissions.getCollaborative()){
            closeRoom(String.valueOf(articleId));
        }
        Article articleNew = new Article();
        articleNew.setId(articleId);
        articleNew.setPermissions(JSON.toJSONString(permissions));
        return updateById(articleNew);
    }

    @Override
    public boolean deleteArticlesById(HttpServletRequest request, long[] ids) {
        UserVo userVo = userService.getUserVo(request);
        if (userVo == null) {
            throw new BusinessException(StateCode.NOT_LOGIN_ERROR);
        }
        long userId = userVo.getId();
        for (long id : ids) {
            Map<String, Object> map = new HashMap<>() {{
                put("id", id);
                put("user_id", userId);
            }};
            this.removeByMap(map);
        }
        return true;
    }

    @Override
    public boolean checkPermission(CheckPermissionRequest checkPermissionRequest) {
        String sessionId = checkPermissionRequest.getSessionId();
        String articleId = checkPermissionRequest.getArticleId();
        UserVo userVo = userService.getUserVo(sessionId);
        if (userVo == null) {
            throw new BusinessException(StateCode.NOT_LOGIN_ERROR);
        }
        Article article = getById(articleId);
        if (article == null) {
            return false;
        }
        if (userVo.getId() == article.getUserId()) {
            return true;
        }
        Permissions permissions = Permissions.str2obj(article.getPermissions());
        List<Integer> collaborators = permissions.getCollaborators();
        for (Integer collaborator : collaborators) {
            if (collaborator == userVo.getId()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void updateCollaborationArticle(ArticleCollaborativeUpdateRequest articleCollaborativeUpdateRequest) {
        String room = articleCollaborativeUpdateRequest.getRoom();
        String content = articleCollaborativeUpdateRequest.getContent();
        String signature = articleCollaborativeUpdateRequest.getSignature();


        // 签名校验
        String generatedSignature = DigestUtil.sha256Hex(SALT+"room_" + room + "content_" + content);
        if (!generatedSignature.equals(signature)) {
            return;
        }
        redisTemplate.opsForSet().add("article_collaboration_active_set", "article_collaboration_room_" + room);
        redisTemplate.opsForValue().set("article_collaboration_room_" + room, content, 1, TimeUnit.MINUTES);
    }

    @Override
    public Permissions getPermissionsById(HttpServletRequest request, IdRequest idRequest) {
        long id = idRequest.getId();

        UserVo userVo = userService.getUserVo(request);
        if (userVo == null) {
            throw new BusinessException(StateCode.NOT_LOGIN_ERROR);
        }
        Article article = this.getById(id);
        if (userVo.getId() != article.getUserId()) {
            throw new BusinessException(StateCode.NO_AUTH_ERROR);
        }
        return Permissions.str2obj(article.getPermissions());
    }

    private void closeRoom(String room) {
        String timestamp = String.valueOf(System.currentTimeMillis());
        String signature = DigestUtil.sha256Hex(SALT+"room_" + room + "timeStamp_" + timestamp);
        HttpRequest.post(roomClosePath)
                .header("timestamp", timestamp)
                .header("room", String.valueOf(room))
                .header("signature", signature)
                .execute();
    }
}




